home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Think Class Libraries / CPixMap.p 1.0 / CPixMap.p next >
Encoding:
Text File  |  1996-02-04  |  26.8 KB  |  848 lines  |  [TEXT/PJMM]

  1. {****************************************************}
  2. {}
  3. {        CPixMap.p                                                                                                                                                                                                                }
  4. {}
  5. {        SUPERCLASS = CBitMap                                                                                                                                                                    }
  6. {}
  7. {        Copyright © 1996 Patrick C Hew. All rights reserved.                                                                        }
  8. {}
  9. {        Based on CColorBitMap.c Code by John A Love, III                                                                                        }
  10. {        email : jlove@aol.com                                                                                                                                                                            }
  11. {}
  12. {        Translated from CPixMap.cp Code by Marty R Wachter                                                                        }
  13. {        email : mrw@welchgate.welch     or afaMarty@aol.com                                                                                }
  14. {}
  15. {        The principal focus of the other files is to OVERRIDE the THINK Class Library's    }
  16. {        "CBitMap" and "CBitMapPane" classes to accomodate color.                                                            }
  17. {}
  18. {        The principal foundation of this work rests with Forrest Tanaka 's    Macintosh        }
  19. {        Technical Note #120. Other, though lesser, key points are :                                                            }
  20. {}
  21. {        •    I have introduced a new instance variable of CBitMapPane in my                                        }
  22. {                CColorBitMapPane class which I call "bitsUnderPane ". It becomes very                }
  23. {                useful when dragging objects around , vice having to take a "picture" of                 }
  24. {                the entire window or screen as Symantec 's    Art Class demo does.     I must        }
  25. {                admit , however , that I have not YET    figured out how to update this                        }
  26. {                "bitsUnderPane" CColorBitMap with a change in color depth, for example,        }
  27. {                when using the popular "Switch-A-Roo"     FKEY. Please refer to my Update            }
  28. {                method for further insight. By the way, Update works just fine    with                        }
  29. {                "itsBitMap", the on-th -top CBitMap.                                                                                                                        }
  30. {        •    I have made much more prolific comments throughout the source.                                    }
  31. {                I truly hope that they are sufficient to guide you.                                                                                    }
  32. {}
  33. {        Original Author : John A . Love , III email : jlove@aol.com                                                                }
  34. {}
  35. {        Revision History:                                                                                                                                                                                        }
  36. {}
  37. {        Version:    1.0 for TCL 1.1.3 (C)                                                                                                                                                }
  38. {        Date:             1993                                                                                                                                                                                                }
  39. {        Author:        John A Love, III     <jlove@aol.com>                                                                                                            }
  40. {        Notes:            Original release.                                                                                                                                                                }
  41. {}
  42. {        Version:    2.0 for TCL 2.0.3 (C++)                                                                                                                                        }
  43. {        Date:             10 November 1994                                                                                                                                                        }
  44. {        Author:        Marty R Wachter     <mrw@welchgate.welch.jhu.edu> or                                                }
  45. {                                                                                            <afaMarty@aol.com>                                                                                            }
  46. {        Notes:            Added support for real C++ in TCL 2.0 by adding proper,                                        }
  47. {                                    constructors, destructors, class definitions, etc… to conform to                }
  48. {                                    the TCL 2.0 changes.                                                                                                                                                    }
  49. {}
  50. {        Version:    1.0 for TCL 1.1.2 (Pascal)                                                                                                                                    }
  51. {        Date:             28 January 1996                                                                                                                                                            }
  52. {        Author:        Patrick C Hew     <phew@ucc.gu.uwa.edu.au>                                                                                }
  53. {        Notes:            Translated from CPixMap.cp.                                                                                                                            }
  54. {}
  55. {****************************************************}
  56.  
  57.  
  58. unit CPixMap;
  59.  
  60. interface
  61.  
  62.     uses
  63.         TCL, MoreTCL;
  64.  
  65.     const
  66.         kMaxRowBytes = $3FFE;    { Max # of bytes in a row of pixels. }
  67.         kDefaultRes = $00480000;    { Default resolution is 72 DPI; Fixed type. }
  68.         kITabRes = 4;    { Inverse-table resolution. }
  69.  
  70.     { For Error handling in my offscreen map routine(s) }
  71.     const
  72.         NewPortError = -10000;
  73.         DepthError = -12000;
  74.         MaxRowBytesError = -14000;
  75.         NewBaseAddrPtrError = -16000;
  76.         ColorTableError = -18000;
  77.         CreateGDeviceError = -20000;
  78.         NilGDeviceError = -22000;
  79.         ZoomWindowError = -24000;
  80.  
  81.     type
  82.         CPixMap = object(CBitmap)
  83.  
  84.                 saveDevice: GDHandle;
  85.                 savePixMap: PixMapHandle;
  86.                 itsPixMap: PixMapHandle;
  87.                 macBits: Handle;
  88.                 itsColors: CTabHandle;
  89.                 itsMaxDevice: GDHandle;
  90.  
  91.                 { Construct a PixMap object. }
  92.                 procedure IPixMap (width: Integer;
  93.                                             height: Integer;
  94.                                             makePort: Boolean);
  95.  
  96.                 { Destroy a PixMap object, resetting all pointers. }
  97.                 procedure Free;
  98.                 override;
  99.  
  100.                 { Determine whether the pixel at the specified coordinates is black. }
  101.                 { Returns FALSE if the pixel is white or the point is not within the PixMap. }
  102.                 { This method is overriden SOLELY because I need to avoid all reference to }
  103.                 { "macBitMap" in order to NOT have to HLock the "itsPixMap".     }
  104.                 function PixelIsBlack (pixelPos: LongPt): Boolean;
  105.                 override;
  106.  
  107.                 { Set up for drawing to a BitMap. If it doesn't have its own port, }
  108.                 { make it the port bits of the current QuickDraw grafPort. Save the }
  109.                 { current port bits so they can be restored later by the EndDrawing }
  110.                 { method. If it has its own port, save the current port and SetPort }
  111.                 { to the BitMap's port. }
  112.                 procedure BeginDrawing;
  113.                 override;
  114.  
  115.                 { Reset the port to the way it was before the BeginDrawing message }
  116.                 { was sent. If BitMap has its own port, restore the saved Grafport. }
  117.                 { Otherwise, restore the saved bitmap in the current port. }
  118.                 procedure EndDrawing;
  119.                 override;
  120.  
  121.                 { Copy bits from a BitMap to the bit map of the current port. The }
  122.                 { fromRect is a rectangle in this BitMap (source rect), and the }
  123.                 { toRect is a rectangle in the current port's bit map (dest rect). }
  124.                 { maskRgn is a clipping region specified in the same coords as the }
  125.                 { dest rect, i.e., the coords of the current port. A nil maskRgn means }
  126.                 { that no extra clipping is performed. Copying takes place using the }
  127.                 { transfer mode stored in the xferMode instance variable. }
  128.                 procedure CopyFrom (fromRect, toRect: LongRect;
  129.                                             maskRgn: RgnHandle);
  130.                 override;
  131.  
  132.                 { Copy bits to a BitMap from the bit map of the current port. The }
  133.                 { fromRect is a rectangle in the current port's bit map (source rect), }
  134.                 { and the toRect is a rectangle in this BitMap (dest rect). maskRgn is }
  135.                 { a clipping region specified in the same coords as the dest rect, }
  136.                 { i.e., the coords of this BitMap. A nil maskRgn means that no extra }
  137.                 { clipping is performed. Copying takes place using the transfer mode }
  138.                 { stored in the xferMode instance variable. }
  139.                 procedure CBitMap.CopyTo (fromRect, toRect: LongRect;
  140.                                             maskRgn: RgnHandle);
  141.                 override;
  142.  
  143.                 { Return the bounding rectangle of a PixMap. This rectangle defines }
  144.                 { the size and coordinate system of the PixMap. }
  145.                 procedure GetBounds (var theBounds: LongRect);
  146.                 override;
  147.  
  148.                 { Set the coordinates of the top left corner of the bounds of a }
  149.                 { PixMap. This changes the coordinate system of the PixMap. }
  150.                 procedure SetBoundsOrigin (hOrigin, vOrigin: integer);
  151.                 override;
  152.  
  153.                 { Set the location-specific and size-specific information of the pixel map. }
  154.                 { This is a private method. }
  155.                 function SetupPixMap (aPixMap: PixMapHandle;
  156.                                             imageBits: Handle;
  157.                                             bytesPerRow: Integer;
  158.                                             theBounds: Rect): CTabHandle;
  159.  
  160.                 { Build and offscreen device for use with the offscreen pixmap. }
  161.                 { This is a private method. }
  162.                 function CreateGDevice (basePixMap: PixMapHandle): GDHandle;
  163.  
  164.             end; { CPixMap }
  165.  
  166.  
  167. implementation
  168.  
  169.     uses
  170.         LongQD;    { and GestaltEqu, which is included in THINK Pascal automatically. }
  171.  
  172.  
  173. {****************************************************}
  174. {}
  175. {        IPixMap                                                                                                                                                                                                                    }
  176. {}
  177. {        Construct a PixMap object.                                                                                                                                                            }
  178. {}
  179. {****************************************************}
  180.  
  181.     procedure CPixMap.IPixMap (width: Integer;
  182.                                     height: Integer;
  183.                                     makePort: Boolean);
  184.  
  185.         var
  186.             theBounds: Rect;
  187.             qdVersion, tempSeed: LongInt;
  188.             err: OSErr;
  189.             depthIndexed, depthDirect, qd32BitInstalled, savedAlloc: Boolean;
  190.             maxDepth, offRowBytes: Integer;
  191.             sizeOfOff: LongInt;
  192.  
  193.     begin { IPixMap }
  194.         xferMode := srcCopy;
  195.         macPort := nil;
  196.         macBitmap.baseAddr := nil;
  197.         itsPixMap := nil;
  198.         macBits := nil;
  199.         itsColors := nil;
  200.         itsMaxDevice := nil;
  201.  
  202.         { I will ignore "makePort" because my bitMap/pixMap }
  203.         { is intricately tied to the off-screen Port. }
  204.  
  205.         SetRect(theBounds, 0, 0, width, height);
  206.         GetPort(savePort);     { Also used by superclass's BeginDrawing and EndDrawing. }
  207.  
  208.         if not gSystem.hasColorQD then begin
  209.             { A low life machine. }
  210.  
  211.             savedAlloc := SetAllocation(kAllocCanFail);
  212.             macPort := GrafPtr(NewPtrClear(SizeOf(GrafPort)));
  213.             savedAlloc := SetAllocation(savedAlloc);
  214.  
  215.             if macPort = nil then begin
  216.                 FailOSErr(NewPortError);
  217.             end; { if }
  218.  
  219.             OpenPort(macPort);
  220.             maxDepth := 1;
  221.         end { if }
  222.         else begin
  223.             { Has Color Quickdraw. }
  224.  
  225.             savedAlloc := SetAllocation(kAllocCanFail);
  226.             macPort := GrafPtr(NewPtrClear(SizeOf(CGrafPort)));
  227.             savedAlloc := SetAllocation(savedAlloc);
  228.  
  229.             if macPort = nil then begin
  230.                 FailOSErr(NewPortError);
  231.             end; { if }
  232.  
  233.             OpenCPort(CGrafPtr(macPort));
  234.             itsPixMap := CGrafPtr(macPort)^.portPixMap;
  235.  
  236.             maxDepth := itsPixMap^^.pixelSize;
  237.  
  238.             if gSystem.hasGestalt then begin
  239.                 err := Gestalt(gestaltQuickdrawVersion, qdVersion);
  240.                 qd32BitInstalled := qdVersion >= gestalt32BitQD;
  241.             end { if }
  242.             else begin
  243.                 qd32BitInstalled := FALSE;
  244.             end; { else }
  245.  
  246.             depthIndexed := maxDepth <= 8;
  247.             depthDirect := (maxDepth > 8) & qd32BitInstalled;
  248.  
  249.             if not depthIndexed and not depthDirect then begin
  250.                 SetPort(savePort);
  251.                 FailOSErr(DepthError);
  252.             end { if }
  253.         end; { else }
  254.  
  255.         { Before we do ANYthing more, we should set the off-screen's }
  256.         { visRgn to the FULL size of the input rect so the image stays }
  257.         { whole even when the window has been dragged partly beyond}
  258.         { the physical edge ( s ) of the screen. Otherwise, the }
  259.         { (**visRgn).rgnBBox in local coordinates remains equal to }
  260.         { screenBits . bounds as initialized when _Open ( C ) Port was called: }
  261.  
  262.         RectRgn(macPort^.visRgn, theBounds);
  263.         macPort^.portRect := theBounds;
  264.         ClipRect(theBounds);
  265.  
  266.         { We are now ready to calculate the size of the pixel image we will need. }
  267.         { Then we can set the location-specific and size-specific information of }
  268.         { the pixel map by calling SetupPixMap if we have color or stuffing }
  269.         { directly if in black-and-white. }
  270.  
  271.         offRowBytes := (maxDepth * (theBounds.right - theBounds.left) + 15) div 16;
  272.  
  273.         { Make even. }
  274.         if offRowBytes mod 2 <> 0 then begin
  275.             offRowBytes := offRowBytes + 1;
  276.         end; { if }
  277.  
  278.         { Back to bytes. }
  279.         offRowBytes := offRowBytes * 2;
  280.  
  281.         if offRowBytes > kMaxRowBytes then begin
  282.             SetPort(savePort);
  283.             FailOSErr(MaxRowBytesError);
  284.         end; { if }
  285.  
  286.         sizeOfOff := (theBounds.bottom - theBounds.top) * LongInt(offRowBytes);
  287.  
  288.         { Allocate space for the pixel image. }
  289.         savedAlloc := SetAllocation(kAllocCanFail);
  290.         ReserveMem(sizeOfOff); { Around forever. }
  291.         macBits := NewHandleClear(sizeOfOff);
  292.         savedAlloc := SetAllocation(savedAlloc);
  293.  
  294.         if macBits = nil then begin
  295.             SetPort(savePort);
  296.             FailOSErr(NewBaseAddrPtrError); { Bye-Bye !!! }
  297.         end; { if }
  298.  
  299.         HLock(macBits);
  300.  
  301.         { NOTE that we 're filling in the BitMap/PixMap fields of the new Port }
  302.         { directly , so we do NOT call _SetPortBits or _SetCPortPix later : }
  303.  
  304.         if gSystem.hasColorQD then begin
  305.  
  306.             itsColors := SetupPixMap(itsPixMap, macBits, offRowBytes, theBounds);
  307.             if itsColors = nil then begin
  308.                 SetPort(savePort);
  309.                 FailOSErr(ColorTableError);
  310.             end; { if }
  311.  
  312.             itsMaxDevice := CreateGDevice(itsPixMap);
  313.             if itsMaxDevice = nil then begin
  314.                 SetPort(savePort);
  315.                 FailOSErr(CreateGDeviceError);
  316.             end; { if }
  317.  
  318.         end { if }
  319.         else begin
  320.             { Black-and-white }
  321.  
  322.             macPort^.portBits.baseAddr := macBits^;    { macBits is a locked handle. }
  323.             macPort^.portBits.rowBytes := offRowBytes;
  324.             macPort^.portBits.bounds := theBounds;
  325.         end; { else }
  326.  
  327.         SetPort(savePort);
  328.  
  329.         ForceNextPrepare;
  330.     end; { IPixMap }
  331.  
  332.  
  333. {****************************************************}
  334. {}
  335. {        Free                                                                                                                                                                                                                                }
  336. {}
  337. {        Destroy a PixMap object, resetting all pointers.                                                                                            }
  338. {}
  339. {****************************************************}
  340.  
  341.     procedure CPixMap.Free;
  342.  
  343.         var
  344.             theColors: CTabHandle;
  345.  
  346.     begin { Free }
  347.         if macPort <> nil then begin
  348.             if gSystem.hasColorQD then begin
  349.  
  350.                 if itsColors <> nil then begin
  351.                     theColors := itsColors;
  352.                     itsColors := nil;
  353.                     DisposCTable(theColors);
  354.                     theColors := nil;
  355.                 end; { if }
  356.  
  357.                 CloseCPort(CGrafPtr(macPort));
  358.                 itsPixMap := nil;    { For completeness: itsPixMap pointed to the pixel map in macPort. }
  359.  
  360.                 if itsMaxDevice <> nil then begin
  361.                     ForgetHandle(itsMaxDevice^^.gdITable);
  362.                     ForgetHandle(itsMaxDevice);
  363.                     itsMaxDevice := nil;
  364.                 end; { if }
  365.  
  366.             end { if }
  367.             else begin
  368.                 { Yucky B & W }
  369.                 ClosePort(macPort);
  370.             end; { else }
  371.  
  372.             ForgetPtr(macPort);
  373.             macPort := nil;    { So inherited method doesn't try to do this again, otherwise big-time bomb! }
  374.         end; { if }
  375.  
  376.         if macBits <> nil then begin
  377.             HUnlock(macBits);
  378.             ForgetHandle(macBits);
  379.             macBits := nil;
  380.         end; { if }
  381.  
  382.         macBitMap.baseAddr := nil; { No need to repeat yourself !!}
  383.  
  384.         inherited Free;
  385.     end; { Free }
  386.  
  387.  
  388. {****************************************************}
  389. {}
  390. {        PixelIsBlack                                                                                                                                                                                                        }
  391. {}
  392. {        Determine whether the pixel at the specified coordinates is black.                                        }
  393. {        Returns FALSE if the pixel is white or the point is not within the PixMap.                    }
  394. {        This method is overriden SOLELY because I need to avoid all reference to                 }
  395. {        "macBitMap" in order to NOT have to HLock the "itsPixMap".                                                        }
  396. {}
  397. {****************************************************}
  398.  
  399.     function CPixMap.PixelIsBlack (pixelPos: LongPt): Boolean;
  400.  
  401.         var
  402.             hPos, vPos: Integer;
  403.             bitNum: LongInt;
  404.             bounds: LongRect;
  405.             theBitMap: BitMapPtr;
  406.  
  407.     begin { PixelIsBlack }
  408.         GetBounds(bounds);
  409.         if (not PtInLongRect(pixelPos, bounds)) then begin
  410.             PixelIsBlack := FALSE; { Point is not in pixel map. }
  411.         end { if }
  412.         else begin
  413.             if gSystem.hasColorQD then begin
  414.                 { Okay to dereference, since nothing below moves memory. }
  415.                 theBitMap := BitMapPtr(itsPixMap^);
  416.             end { if }
  417.             else begin
  418.                 theBitMap := @thePort^.portBits;
  419.             end; { else }
  420.  
  421.             hPos := pixelPos.h - theBitMap^.bounds.left;
  422.             vPos := pixelPos.v - theBitMap^.bounds.top;
  423.  
  424.             { Point is within BitMap.  Convert point into }
  425.             { a bit offset from the start of the image: }
  426.  
  427.             bitNum := Longint(vPos) * theBitMap^.rowBytes * 8 + hPos;
  428.             PixelIsBlack := BitTst(theBitMap^.baseAddr, bitNum);
  429.  
  430.         end; { else }
  431.     end; { PixelIsBlack }
  432.  
  433.  
  434. {****************************************************}
  435. {}
  436. {        BeginDrawing                                                                                                                                                                                                    }
  437. {}
  438. {        Set up for drawing to a BitMap. If it doesn't have its own port,                                                }
  439. {        make it the port bits of the current QuickDraw grafPort. Save the                                        }
  440. {        current port bits so they can be restored later by the EndDrawing                                        }
  441. {        method. If it has its own port, save the current port and SetPort                                            }
  442. {        to the BitMap's port.}
  443. {}
  444. {****************************************************}
  445.  
  446.     procedure CPixMap.BeginDrawing;
  447.  
  448.     begin { BeginDrawing }
  449.         if macPort = nil then begin
  450.             if gSystem.hasColorQD then begin
  451.                 savePixMap := CGrafPtr(thePort)^.portPixMap;
  452.                 SetPortPix(itsPixMap);
  453.             end { if }
  454.             else begin
  455.                 saveBitMap := thePort^.portBits;
  456.                 SetPortBits(macPort^.portBits);    { Really!? Dereference nil? }
  457.             end; { else }
  458.         end { if }
  459.         else begin
  460.             GetPort(savePort);
  461.             SetPort(macPort);
  462.         end; { else }
  463.  
  464.         if gSystem.hasColorQD then begin
  465.             saveDevice := GetGDevice;
  466.             SetGDevice(itsMaxDevice);
  467.         end; { if }
  468.     end; { BeginDrawing }
  469.  
  470.  
  471. {****************************************************}
  472. {}
  473. {        EndDrawing                                                                                                                                                                                                            }
  474. {}
  475. {        Reset the port to the way it was before the BeginDrawing message                                    }
  476. {        was sent. If BitMap has its own port, restore the saved Grafport.                                        }
  477. {        Otherwise, restore the saved bitmap in the current port.                                                                    }
  478. {}
  479. {****************************************************}
  480.  
  481.     procedure CPixMap.EndDrawing;
  482.  
  483.     begin { EndDrawing }
  484.         if macPort = nil then begin
  485.             if gSystem.hasColorQD then begin
  486.                 SetPortPix(savePixMap);
  487.             end { if }
  488.             else begin
  489.                 SetPortBits(saveBitMap);
  490.             end; { else }
  491.         end { if }
  492.         else begin
  493.             SetPort(savePort);
  494.         end; { else }
  495.  
  496.         if gSystem.hasColorQD then begin
  497.             SetGDevice(saveDevice);
  498.         end; { if }
  499.     end; { EndDrawing }
  500.  
  501.  
  502. {****************************************************}
  503. {}
  504. {        CopyFrom                                                                                                                                                                                                                }
  505. {}
  506. {        Copy bits from a BitMap to the bit map of the current port. The                                                }
  507. {        fromRect is a rectangle in this BitMap (source rect), and the                                                        }
  508. {        toRect is a rectangle in the current port's bit map (dest rect).                                                    }
  509. {        maskRgn is a clipping region specified in the same coords as the                                                }
  510. {        dest rect, i.e., the coords of the current port. A nil maskRgn means                                    }
  511. {        that no extra clipping is performed. Copying takes place using the                                        }
  512. {        transfer mode stored in the xferMode instance variable.                                                                    }
  513. {}
  514. {****************************************************}
  515.  
  516.     procedure CPixMap.CopyFrom (fromRect, toRect: LongRect;
  517.                                     maskRgn: RgnHandle);
  518.  
  519.         var
  520.             saveForeColor, saveBackColor: RGBColor;
  521.             kBlackColor, kWhiteColor: RGBColor;
  522.  
  523.     begin { CopyFrom }
  524.         if gSystem.hasColorQD then begin
  525.             GetForeColor(saveForeColor);
  526.             GetBackColor(saveBackColor);
  527.  
  528.             with kBlackColor do begin
  529.                 red := $0000;
  530.                 green := $0000;
  531.                 blue := $0000;
  532.             end; { with }
  533.             with kWhiteColor do begin
  534.                 red := $FFFF;
  535.                 green := $FFFF;
  536.                 blue := $FFFF;
  537.             end; { with }
  538.  
  539.             RGBForeColor(kBlackColor);
  540.             RGBBackColor(kWhiteColor);
  541.         end; { if }
  542.  
  543.         LCopyBits(macPort^.portBits, thePort^.portBits, fromRect, toRect, xferMode, maskRgn);
  544.  
  545.         if gSystem.hasColorQD then begin
  546.             RGBForeColor(saveForeColor);
  547.             RGBBackColor(saveBackColor);
  548.         end; { if }
  549.     end; { CopyFrom }
  550.  
  551.  
  552. {****************************************************}
  553. {}
  554. {        CopyTo                                                                                                                                                                                                                        }
  555. {}
  556. {        Copy bits to a BitMap from the bit map of the current port. The                                                }
  557. {        fromRect is a rectangle in the current port's bit map (source rect),                                    }
  558. {        and the toRect is a rectangle in this BitMap (dest rect). maskRgn is                                    }
  559. {        a clipping region specified in the same coords as the dest rect,                                                    }
  560. {        i.e., the coords of this BitMap. A nil maskRgn means that no extra                                        }
  561. {        clipping is performed. Copying takes place using the transfer mode                                        }
  562. {        stored in the xferMode instance variable.                                                                                                                }
  563. {}
  564. {****************************************************}
  565.  
  566.     procedure CPixMap.CopyTo (fromRect, toRect: LongRect;
  567.                                     maskRgn: RgnHandle);
  568.  
  569.         var
  570.             kBlackColor, kWhiteColor: RGBColor;
  571.  
  572.     begin { CopyTo }
  573.         BeginDrawing;
  574.  
  575.         if gSystem.hasColorQD then begin
  576.             with kBlackColor do begin
  577.                 red := $0000;
  578.                 green := $0000;
  579.                 blue := $0000;
  580.             end; { with }
  581.             with kWhiteColor do begin
  582.                 red := $FFFF;
  583.                 green := $FFFF;
  584.                 blue := $FFFF;
  585.             end; { with }
  586.  
  587.             RGBForeColor(kBlackColor);
  588.             RGBBackColor(kWhiteColor);
  589.         end; { if }
  590.  
  591.         LCopyBits(thePort^.portBits, macPort^.portBits, fromRect, toRect, xferMode, maskRgn);
  592.  
  593.         EndDrawing;
  594.     end; { CopyTo }
  595.  
  596.  
  597. {****************************************************}
  598. {}
  599. {        GetBounds                                                                                                                                                                                                                }
  600. {}
  601. {        Return the bounding rectangle of a PixMap. This rectangle defines                                        }
  602. {        the size and coordinate system of the PixMap.                                                                                                    }
  603. {}
  604. {****************************************************}
  605.  
  606.     procedure CPixMap.GetBounds (var theBounds: LongRect);
  607.  
  608.         var
  609.             itsBounds: Rect;
  610.  
  611.     begin { GetBounds }
  612.         if gSystem.hasColorQD then begin
  613.             itsBounds := itsPixMap^^.bounds;
  614.         end { if }
  615.         else begin
  616.             itsBounds := macPort^.portBits.bounds;
  617.         end; { else }
  618.         QDToLongRect(itsBounds, theBounds);
  619.     end; { GetBounds }
  620.  
  621.  
  622. {****************************************************}
  623. {}
  624. {        SetBoundsOrigin                                                                                                                                                                                            }
  625. {}
  626. {        Set the coordinates of the top left corner of the bounds of a                                                            }
  627. {        PixMap. This changes the coordinate system of the PixMap.                                                            }
  628. {}
  629. {****************************************************}
  630.  
  631.     procedure CPixMap.SetBoundsOrigin (hOrigin, vOrigin: Integer);
  632.  
  633.         var
  634.             newLBounds: LongRect;
  635.             newSBounds: Rect;
  636.  
  637.     begin { SetBoundsOrigin }
  638.         if not (gSystem.hasColorQD & ((itsPixMap = nil) | (itsMaxDevice = nil))) then begin
  639.  
  640.             GetBounds(newLBounds);
  641.  
  642.             { The next four lines correspond to the inherited method. }
  643.             newLBounds.right := newLBounds.right + hOrigin - newLBounds.left;
  644.             newLBounds.bottom := newLBounds.bottom + vOrigin - newLBounds.top;
  645.             newLBounds.left := hOrigin;
  646.             newLBounds.top := vOrigin;
  647.  
  648.             LongToQDRect(newLBounds, newSBounds);
  649.  
  650.             RectRgn(gUtilRgn, newSBounds);        { Can't pass instance variable directly, }
  651.             macPort^.visRgn := gUtilRgn;                { because RectRgn moves memory. }
  652.             macPort^.portRect := newSBounds;
  653.             macPort^.clipRgn := gUtilRgn;
  654.  
  655.             if gSystem.hasColorQD then begin
  656.                 itsPixMap^^.bounds := newSBounds;
  657.                 {  itsMaxDevice^^.gdPMap := itsPixMap; }
  658.                 itsMaxDevice^^.gdRect := newSBounds;
  659.             end { if }
  660.             else begin
  661.                 macPort^.portBits.bounds := newSBounds;
  662.             end; { else }
  663.         end; { if }
  664.     end; { SetBoundsOrigin }
  665.  
  666.  
  667. {****************************************************}
  668. {}
  669. {        SetupPixMap                                                                                                                                                                                                        }
  670. {}
  671. {        Set the location-specific and size-specific information of the pixel map.                        }
  672. {        This is a private method.                                                                                                                                                                    }
  673. {}
  674. {****************************************************}
  675.  
  676.     function CPixMap.SetupPixMap (aPixMap: PixMapHandle;
  677.                                     imageBits: Handle;
  678.                                     bytesPerRow: Integer;
  679.                                     theBounds: Rect): CTabHandle;
  680.  
  681.         var
  682.             newColors: CTabHandle; { Color table used for the offscreen PixMap. }
  683.             depth: Integer;
  684.             savedAlloc: Boolean;
  685.             error: OSErr;
  686.  
  687.     begin { SetupPixMap }
  688.         ASSERT(aPixMap <> nil);
  689.  
  690.         newColors := nil;
  691.         depth := aPixMap^^.pixelSize;
  692.  
  693.         { Clone the clut if indexed color; allocate a dummy clut if direct color. }
  694.         savedAlloc := SetAllocation(kAllocCanFail);
  695.  
  696.         if depth <= 8 then begin
  697.             newColors := aPixMap^^.pmTable;
  698.             error := HandToHand(Handle(newColors));
  699.         end { if }
  700.         else begin
  701.             newColors := CTabHandle(NewHandleClear(SizeOf(ColorTable) - SizeOf(CSpecArray)));
  702.             error := MemError;
  703.         end; { else }
  704.  
  705.         savedAlloc := SetAllocation(savedAlloc);
  706.  
  707.         if error <> noErr then begin
  708.             SetupPixMap := nil;
  709.         end { if }
  710.         else begin
  711.             { Initialize fields common to indexed and direct PixMaps. }
  712.  
  713.             aPixMap^^.baseAddr := imageBits^;    { This is a safe assignment; imageBits is locked. }
  714.             aPixMap^^.rowBytes := BitOr(bytesPerRow, $8000);    { MSB set for PixMap. }
  715.             aPixMap^^.bounds := theBounds;
  716.             aPixMap^^.pmVersion := 0; { No special stuff. }
  717.             aPixMap^^.packType := 0; { Default PICT pack. }
  718.             aPixMap^^.packSize := 0; { Always zero in memory. }
  719.             aPixMap^^.hRes := kDefaultRes; { 72 DPI default res. }
  720.             aPixMap^^.vRes := kDefaultRes; { 72 DPI default res. }
  721.             { aPixMap^^.pixelSize := depth;  -- Already done. }
  722.             aPixMap^^.planeBytes := 0; { Not used. }
  723.             aPixMap^^.pmReserved := 0; { Not used. }
  724.  
  725.             { Initialize the fields specific to indexed and direct PixMaps. }
  726.  
  727.             if depth <= 8 then begin
  728.                 aPixMap^^.pixelType := 0; { Indicates indexed. }
  729.                 aPixMap^^.cmpCount := 1; { Have 1 component. }
  730.                 aPixMap^^.cmpSize := depth; { Component size = depth. }
  731.                 aPixMap^^.pmTable := newColors; { Handle to CLUT. }
  732.             end { if }
  733.             else begin
  734.                 aPixMap^^.pixelType := RGBDirect; { Indicates direct. }
  735.                 aPixMap^^.cmpCount := 3; { Have 3 components. }
  736.                 if depth = 16 then begin
  737.                     aPixMap^^.cmpSize := 5;     { 5 bits/component.     }
  738.                 end { if }
  739.                 else begin
  740.                     aPixMap^^.cmpSize := 8;     { 8 bits/component. }
  741.                 end; { else }
  742.                 newColors^^.ctSeed := 3 * aPixMap^^.cmpSize;
  743.                 newColors^^.ctFlags := 0;
  744.                 newColors^^.ctSize := 0;
  745.                 aPixMap^^.pmTable := newColors;
  746.             end; { else }
  747.  
  748.             SetupPixMap := newColors;
  749.         end; { else }
  750.     end; { SetupPixMap }
  751.  
  752.  
  753. {****************************************************}
  754. {}
  755. {        CreateGDevice                                                                                                                                                                                                }
  756. {}
  757. {        Build and offscreen device for use with the offscreen pixmap.                                                    }
  758. {        This is a private method.                                                                                                                                                                 }
  759. {}
  760. {****************************************************}
  761.  
  762.     function CPixMap.CreateGDevice (basePixMap: PixMapHandle): GDHandle;
  763.  
  764.         var
  765.             newDevice: GDHandle; { Handle to the new GDevice.}
  766.             embryoITab: ITabHandle; { Handle to the embryonic inverse table. }
  767.             savedAlloc: Boolean;
  768.             deviceRect: Rect;        { Rectangle of GDevice. }
  769.             depth: Integer;
  770.  
  771.     begin { CreateGDevice }
  772.         { Initialize a few things before we begin. }
  773.         newDevice := nil;
  774.         embryoITab := nil;
  775.  
  776.         { Allocate memory for the new GDevice. }
  777.         savedAlloc := SetAllocation(kAllocCanFail);
  778.         newDevice := GDHandle(NewHandleClear(SizeOf(GDevice)));
  779.         savedAlloc := SetAllocation(savedAlloc);
  780.  
  781.         if newDevice <> nil then begin
  782.  
  783.             { Allocate the embryonic inverse table. }
  784.             savedAlloc := SetAllocation(kAllocCanFail);
  785.             embryoITab := ITabHandle(NewHandleClear(2));
  786.             savedAlloc := SetAllocation(savedAlloc);
  787.  
  788.             if embryoITab = nil then begin
  789.                 ForgetHandle(newDevice);
  790.                 newDevice := nil;
  791.             end
  792.             else begin
  793.  
  794.                 { Set rectangle of device to PixMap bounds. }
  795.                 deviceRect := basePixMap^^.bounds;
  796.  
  797.                 depth := basePixMap^^.pixelSize;
  798.  
  799.                 { Initialize the new GDevice fields. }
  800.                 newDevice^^.gdRefNum := 0; { Only used for screens. }
  801.                 newDevice^^.gdID := 0; {Won’t normally use. }
  802.                 if depth <= 8 then begin
  803.                     newDevice^^.gdType := clutType; { Depth ≤ 8; clut device. }
  804.                 end { if }
  805.                 else begin
  806.                     newDevice^^.gdType := directType; { Depth > 8; direct device. }
  807.                 end; { else }
  808.                 newDevice^^.gdITable := embryoITab;    { 2-byte handle for now. }
  809.                 newDevice^^.gdResPref := kITabRes; { Normal inv table res. }
  810.                 newDevice^^.gdSearchProc := nil; { No color-search proc. }
  811.                 newDevice^^.gdCompProc := nil; { No complement proc. }
  812.                 newDevice^^.gdFlags := 0;     { Will set these below. }
  813.                 newDevice^^.gdPMap := basePixMap;    { Reference our PixMap. }
  814.                 newDevice^^.gdRefCon := 0; { Won’t normally use. }
  815.                 newDevice^^.gdNextGD := nil;     { Not in GDevice list. }
  816.                 newDevice^^.gdRect := deviceRect;    { Use PixMap dimensions. }
  817.                 newDevice^^.gdMode := -1; { For non-screens. }
  818.                 newDevice^^.gdCCBytes := 0; { Only used for screens. }
  819.                 newDevice^^.gdCCDepth := 0; { Only used for screens. }
  820.                 newDevice^^.gdCCXData := nil; { Only used for screens. }
  821.                 newDevice^^.gdCCXMask := nil; { Only used for screens. }
  822.                 newDevice^^.gdReserved := 0;     { Currently unused. }
  823.  
  824.                 { Set color-device bit if PixMap isn’t black & white. }
  825.                 if depth > 1 then begin
  826.                     SetDeviceAttribute(newDevice, gdDevType, true);
  827.                 end; { if }
  828.  
  829.                 { Set bit to indicate that the GDevice has no video driver. }
  830.                 SetDeviceAttribute(newDevice, noDriver, true);
  831.  
  832.                 { Initialize the inverse table. }
  833.                 if depth <= 8 then begin
  834.                     MakeITable(basePixMap^^.pmTable, newDevice^^.gdITable, newDevice^^.gdResPref);
  835.                     if QDError <> noErr then begin
  836.                         ForgetHandle(newDevice);
  837.                         ForgetHandle(embryoITab);
  838.                         newDevice := nil;
  839.                     end; { if }
  840.                 end; { if }
  841.             end; { else }
  842.         end; { if }
  843.  
  844.         CreateGDevice := newDevice;
  845.     end; { CreateGDevice }
  846.  
  847.  
  848. end. { CPixMap }